package org.hackystat.devcathlon.engine.event;

import java.util.List;

import javax.xml.datatype.XMLGregorianCalendar;
import org.hackystat.devcathlon.engine.db.hibernate.HibernateUtil;
import org.hackystat.devcathlon.engine.match.Match;
import org.hackystat.devcathlon.engine.team.Team;
import org.hackystat.devcathlon.engine.team.TeamManager;
import org.hackystat.devcathlon.engine.user.User;
import org.hibernate.HibernateException;
import org.hibernate.Query;
import org.hibernate.Session;
import org.hibernate.Transaction;

/**
 * Event Score Manager for dealing with computations of event scores.
 * 
 * @author Anthony Du
 *
 */
public class EventScoreManager {
  /** The singleton instance of this class. */
  private static EventScoreManager theInstance = new EventScoreManager();
  
  /** The private constructor. */
  private EventScoreManager() {
    // empty constructor
  }

  /**
   * Returns the singleton instance of the EventManager.
   * 
   * @return The EventManager.
   */
  public static EventScoreManager getInstance() {
    return EventScoreManager.theInstance;
  }
  
  /**
   * Adds an event score to the system.
   * 
   * @param timestamp The timestamp.
   * @param match The match.
   * @param team The team.
   * @return The event score.
   */
  public synchronized EventScore addEventScore(XMLGregorianCalendar timestamp, 
      Match match, Team team) {
    
    EventScore eventScore = null;
    Session session = HibernateUtil.getSessionFactory().getCurrentSession();
    try {
      session.beginTransaction();
      eventScore = new EventScore(timestamp, match, team);
      session.save(eventScore);
      session.getTransaction().commit();
    }
    catch (HibernateException ex) {
      Transaction tx = session.getTransaction();
      if (tx.isActive()) {
        tx.rollback();
      }
      throw ex;
    }
    return eventScore;
  }
  
  /**
   * Adds an event score to the system.
   * 
   * @param timestamp The timestamp
   * @param match The match.
   * @param team The team.
   * @param user The user.
   * @return The event score.
   */
  public synchronized EventScore addEventScore(XMLGregorianCalendar timestamp, Match match, 
      Team team, User user) {
    EventScore eventScore = null;
    Session session = HibernateUtil.getSessionFactory().getCurrentSession();
    try {
      session.beginTransaction();
      eventScore = new EventScore(timestamp, match, team, user);
      session.save(eventScore);
      session.getTransaction().commit();
    }
    catch (HibernateException ex) {
      Transaction tx = session.getTransaction();
      if (tx.isActive()) {
        tx.rollback();
      }
      throw ex;
    }
    return eventScore;
  }
  
  /**
   * Updates a given event score.
   * 
   * @param eventScore The event score.
   * @return The updated event score. 
   */
  public synchronized EventScore updateEventScore(EventScore eventScore) {
    Session session = HibernateUtil.getSessionFactory().getCurrentSession();
    try {
      session.beginTransaction();
      session.saveOrUpdate(eventScore);
      session.getTransaction().commit();
    }
    catch (HibernateException ex) {
      Transaction tx = session.getTransaction();
      if (tx.isActive()) {
        tx.rollback();
      }
      throw ex;
    }
    return eventScore;
  }

  /**
   * Returns the event score.
   * 
   * @param timestamp The timestamp
   * @return The event score.
   */
  public synchronized EventScore getEventScore(XMLGregorianCalendar timestamp) {
    EventScore eventScore = null;
    if (null == timestamp) {
      return eventScore;
    }
    String hqlSelect = "from EventScore t where t.timeReceived = :timeReceived";
    
    Session session = HibernateUtil.getSessionFactory().getCurrentSession();
    try {
      session.beginTransaction();
      Query query = session.createQuery(hqlSelect).setString("timeReceived", timestamp.toString());
      eventScore = (EventScore) query.uniqueResult();
      session.getTransaction().commit();
    }
    catch (HibernateException ex) {
      Transaction tx = session.getTransaction();
      if (tx.isActive()) {
        tx.rollback();
      }
      throw ex;
    }
    
    return eventScore; 
  }
  
  /**
   * Returns all event scores associated with a given team.
   * 
   * @param team The event score's team.
   * @return The event scores list
   */
  @SuppressWarnings("unchecked")
  public synchronized List<EventScore> getEventScore(Team team) {
    List<EventScore> eventScores = null;
    String hqlSelect = "from EventScore e where e.team = :team";
    
    Session session = HibernateUtil.getSessionFactory().getCurrentSession();
    try {
      session.beginTransaction();
      Query query = session.createQuery(hqlSelect).setLong("team", team.getId());
      eventScores = (List<EventScore>) query.list();
      session.getTransaction().commit();
    }
    catch (HibernateException ex) {
      Transaction tx = session.getTransaction();
      if (tx.isActive()) {
        tx.rollback();
      }
      throw ex;
    }
    return eventScores;
  }
  
  /**
   * Delete the event score.
   * 
   * @param timestamp The timestamp of this event score.
   */
  public synchronized void deleteEventScore(XMLGregorianCalendar timestamp) {
    EventScore eventScore = getEventScore(timestamp);
    if (null == eventScore) {
      return;
    }
    
    Session session = HibernateUtil.getSessionFactory().getCurrentSession();
    try {
      session.beginTransaction();
      session.delete(eventScore);
      session.getTransaction().commit();
    }
    catch (HibernateException ex) {
      Transaction tx = session.getTransaction();
      if (tx.isActive()) {
        tx.rollback();
      }
      throw ex;
    }
  }
  
  /**
   * Deletes the event score given the team.
   * 
   * @param teamName The team name.
   */
  public synchronized void deleteEventScore(String teamName) {
    // Retrieve the team object
    Team team = TeamManager.getInstance().getTeam(teamName);
    // Retrieve all event scores associated to that team.
    List<EventScore> eventScores = getEventScore(team);
    
    if (null == team || eventScores.isEmpty()) {
      return;
    }
    
    Session session = HibernateUtil.getSessionFactory().getCurrentSession();
    try {
      session.beginTransaction();
      for (EventScore eventScore : eventScores) {
        session.delete(eventScore);
      }
      session.getTransaction().commit();
    }
    catch (HibernateException ex) {
      Transaction tx = session.getTransaction();
      if (tx.isActive()) {
        tx.rollback();
      }
      throw ex;
    }
  }
  
  /**
   * Gets the calculated event score.
   * 
   */
  // match.addScore
}
